#pragma once 

#include <iostream>
#include <queue>
#include <pthread.h>

#include "Task.hpp"
#include "Log.hpp"

#define NUM 10

class ThreadPool{
  private:
    std::queue<Task> task_queue;
    int num_;//创建的线程数
    bool stop;

    pthread_mutex_t lock;
    pthread_cond_t cond;
    ThreadPool(int num = NUM):num_(num), stop(false){
     pthread_mutex_init(&lock, nullptr);
     pthread_cond_init(&cond, nullptr);
    }
    ThreadPool(const ThreadPool& tp) = delete;

    static ThreadPool* single_instance;
  public:
    static ThreadPool* GetInstance(){
      static pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
      if(single_instance == nullptr){//减少锁的争用，提高效率
        pthread_mutex_lock(&mutex_);
        if(single_instance == nullptr){//保护线程安全
          single_instance = new ThreadPool();
          single_instance->InitThreadPool();

        }
        pthread_mutex_unlock(&mutex_);
      }
      return single_instance;
    }
   bool TaskQueueIsEmpty(){
     return task_queue.size() == 0 ? true : false;
   }
   void Lock(){
     pthread_mutex_lock(&lock);
   }
   void Unlock(){
     pthread_mutex_unlock(&lock);
   }
   bool IsStop(){
     return stop;
   }
   void ThreadWait(){
     pthread_cond_wait(&cond, &lock);
   }
   void ThreadWakeUp(){
     pthread_cond_signal(&cond);
   }
   static void* ThreadRoutine(void* args){
     ThreadPool* tp = (ThreadPool*)args;
     while(1){
       Task t;
       tp->Lock();
       while(tp->TaskQueueIsEmpty()){
         tp->ThreadWait();//当被唤醒的时候一定时占有互斥锁的
       }
       tp->PopTask(t);
       tp->Unlock();
       t.ProcessOn();
     }
   }
   bool InitThreadPool(){
     for(int i = 0; i < num_; i++){
       pthread_t tid;
       if(pthread_create(&tid, nullptr, ThreadRoutine, this) != 0){
         LOG(FATAL, "create thread pool error!");
         return false;
       }
     }
     LOG(INFO, "create thread pool success!");
     return true;
   }
   void PushTask(const Task& task){
     Lock();
     task_queue.push(task);
     Unlock();
     ThreadWakeUp();
   }
   void PopTask(Task& task){
     task = task_queue.front();
     task_queue.pop();
   }
   ~ThreadPool(){
     pthread_mutex_destroy(&lock);
     pthread_cond_destroy(&cond);
   }
};

ThreadPool* ThreadPool::single_instance = nullptr;
